var MachO = function() {
    this.__class__ = arguments.callee;
    this.initialize.apply(this, arguments);
};

MachO.Segment = function() {
    this.__class__ = arguments.callee;
    this.initialize.apply(this, arguments);
};

jQuery.extend(MachO.Segment, {
    S_REGULAR: 0x0,
    S_ZEROFILL: 0x1,
    S_CSTRING_LITERALS: 0x2,
    S_4BYTE_LITERALS: 0x3,
    S_8BYTE_LITERALS: 0x4,
    S_LITERAL_POINTERS: 0x5,
    S_NON_LAZY_SYMBOL_POINTERS: 0x6,
    S_LAZY_SYMBOL_POINTERS: 0x7,
    S_SYMBOL_STUBS: 0x8,
    S_MOD_INIT_FUNC_POINTERS: 0x9,
    S_MOD_TERM_FUNC_POINTERS: 0xa,
    S_COALESCED: 0xb,
    S_GB_ZEROFILL: 0xc,
    S_INTERPOSING: 0xd,
    S_16BYTE_LITERALS: 0xe,
    S_DTRACE_DOF: 0xf,
    SECTION_ATTRIBUTES_USR: 0xff000000,
    S_ATTR_PURE_INSTRUCTIONS: 0x80000000,
    S_ATTR_NO_TOC: 0x40000000,
    S_ATTR_STRIP_STATIC_SYMS: 0x20000000,
    S_ATTR_NO_DEAD_STRIP: 0x10000000,
    S_ATTR_LIVE_SUPPORT: 0x08000000,
    S_ATTR_SELF_MODIFYING_CODE: 0x04000000,
    S_ATTR_DEBUG: 0x02000000,
    SECTION_ATTRIBUTES_SYS: 0x00ffff00,
    S_ATTR_SOME_INSTRUCTIONS: 0x00000400,
    S_ATTR_EXT_RELOC: 0x00000200,
    S_ATTR_LOC_RELOC: 0x00000100
});

MachO.Segment.prototype = {
    name: '',
    vmaddr: 0,
    vmsize: 0,
    fileoff: 0,
    filesize: 0,
    maxprot: 0,
    initprot: 0,
    flags: 0,
    sections: null,

    initialize: function(name) {
        this.name = name;
        this.vmaddr = 0;
        this.vmsize = 0;
        this.fileoff = 0;
        this.filesize = 0;
        this.maxprot = 0;
        this.initprot = 0;
        this.flags = 0;
        this.sections = [];
    },

    addSection: function(name) {
        var sect = {
            name: name,
            seg: this,
            addr: 0,
            size: 0,
            offset: 0,
            align: 0,
            reloff: 0,
            nreloc: 0,
            flags: 0
        };
        this.sections.push(sect);
        return sect;
    }
};

jQuery.extend(MachO, {
    MH_OBJECT: 0x1,		
    MH_EXECUTE: 0x2,		
    MH_FVMLIB: 0x3,		
    MH_CORE: 0x4,		
    MH_PRELOAD: 0x5,		
    MH_DYLIB: 0x6,		
    MH_DYLINKER: 0x7,		
    MH_BUNDLE: 0x8,		
    MH_DYLIB_STUB: 0x9,		
    MH_DSYM: 0xa,		
    MH_NOUNDEFS: 0x1,		
    MH_INCRLINK: 0x2,		
    MH_DYLDLINK: 0x4,		
    MH_BINDATLOAD: 0x8,		
    MH_PREBOUND: 0x10,		
    MH_SPLIT_SEGS: 0x20,		
    MH_LAZY_INIT: 0x40,		
    MH_TWOLEVEL: 0x80,		
    MH_FORCE_FLAT: 0x100,		
    MH_NOMULTIDEFS: 0x200,		
    MH_NOFIXPREBINDING: 0x400,
    MH_PREBINDABLE: 0x800,
    MH_ALLMODSBOUND: 0x1000, 
    MH_SUBSECTIONS_VIA_SYMBOLS: 0x2000,
    MH_CANONICAL: 0x4000,
    MH_WEAK_DEFINES: 0x8000,
    MH_BINDS_TO_WEAK: 0x10000,
    MH_ALLOW_STACK_EXECUTION: 0x20000,
    MH_ROOT_SAFE: 0x40000,
    MH_SETUID_SAFE: 0x80000,
    MH_NO_REEXPORTED_DYLIBS: 0x100000,
    MH_PIE: 0x200000,

    HEADER_SIZE: 28,
    SECT_SIZE: 68,
    LC_SIZE_SEGMENT: 56,
    LC_SIZE_SYMTAB: 40,
    LC_SIZE_DYSYMTAB: 80,
    LC_SIZE_UNIXTHREAD_X86: 92,
    LC_SIZE_UNIXTHREAD_X86_64: 184,
    LC_SIZE_UNIXTHREAD_POWERPC: 176,
    LC_SIZE_UNIXTHREAD_POWERPC64: 320,

    CPU_TYPE_X86: 0x07,
    CPU_TYPE_X86_64: 0x01000007,
    CPU_TYPE_POWERPC: 0x12,
    CPU_TYPE_POWERPC64: 0x01000012,
    CPU_THREADTYPE_NONE: 0,
    CPU_THREADTYPE_INTEL_HTT: 1,
    CPU_SUBTYPE_MASK: 0xff000000,
    CPU_SUBTYPE_LIB64: 0x80000000,
    CPU_SUBTYPE_MULTIPLE:  -1,
    CPU_SUBTYPE_LITTLE_ENDIAN:  0,
    CPU_SUBTYPE_BIG_ENDIAN:  1,
    CPU_SUBTYPE_I386_ALL: 0x03,
    CPU_SUBTYPE_386: 0x03,
    CPU_SUBTYPE_486: 0x04,
    CPU_SUBTYPE_486SX: 0x84,
    CPU_SUBTYPE_586: 0x05,
    CPU_SUBTYPE_PENT: 0x05,
    CPU_SUBTYPE_PENTPRO: 0x16,
    CPU_SUBTYPE_PENTII_M3: 0x36,
    CPU_SUBTYPE_PENTII_M5: 0x56,
    CPU_SUBTYPE_CELERON: 0x67,
    CPU_SUBTYPE_CELERON_MOBILE: 0x77,
    CPU_SUBTYPE_PENTIUM_3: 0x08,
    CPU_SUBTYPE_PENTIUM_3_M: 0x18,
    CPU_SUBTYPE_PENTIUM_3_XEON: 0x28,
    CPU_SUBTYPE_PENTIUM_M: 0x09,
    CPU_SUBTYPE_PENTIUM_4: 0x0a,
    CPU_SUBTYPE_PENTIUM_4_M: 0x1a,
    CPU_SUBTYPE_ITANIUM: 0x0b,
    CPU_SUBTYPE_ITANIUM_2: 0x1b,
    CPU_SUBTYPE_XEON: 0x0c,
    CPU_SUBTYPE_XEON_MP: 0x1c,
    CPU_SUBTYPE_X86_ALL: 3,
    CPU_SUBTYPE_X86_64_ALL: 3,
    CPU_SUBTYPE_POWERPC_ALL: 0,
    CPU_SUBTYPE_POWERPC_601: 1,
    CPU_SUBTYPE_POWERPC_602: 2,
    CPU_SUBTYPE_POWERPC_603: 3,
    CPU_SUBTYPE_POWERPC_603e: 4,
    CPU_SUBTYPE_POWERPC_603ev: 5,
    CPU_SUBTYPE_POWERPC_604: 6,
    CPU_SUBTYPE_POWERPC_604e: 7,
    CPU_SUBTYPE_POWERPC_620: 8,
    CPU_SUBTYPE_POWERPC_750: 9,
    CPU_SUBTYPE_POWERPC_7400: 10,
    CPU_SUBTYPE_POWERPC_7450: 11,
    CPU_SUBTYPE_POWERPC_970: 100,

    PPC_THREAD_STATE:       1,
    PPC_FLOAT_STATE:        2,
    PPC_EXCEPTION_STATE:    3,
    PPC_VECTOR_STATE:       4,
    PPC_THREAD_STATE64:     5,
    PPC_EXCEPTION_STATE64:  6,

    i386_THREAD_STATE:      1,
    i386_FLOAT_STATE:       2,
    i386_EXCEPTION_STATE:   3,

    x86_THREAD_STATE32: 1,
    x86_FLOAT_STATE32: 2,
    x86_EXCEPTION_STATE32: 3,
    x86_THREAD_STATE64: 4,
    x86_FLOAT_STATE64: 5,
    x86_EXCEPTION_STATE64: 6,
    x86_THREAD_STATE: 7,
    x86_FLOAT_STATE: 8,
    x86_EXCEPTION_STATE: 9,
    x86_DEBUG_STATE32: 10,
    x86_DEBUG_STATE64: 11,
    x86_DEBUG_STATE: 12,
    THREAD_STATE_NONE: 13,

    SEG_PAGEZERO: "__PAGEZERO",
    SEG_TEXT: "__TEXT",
    SECT_TEXT: "__text",
    SECT_FVMLIB_INIT0: "__fvmlib_init0",
    SECT_FVMLIB_INIT1: "__fvmlib_init1",
    SEG_DATA: "__DATA",
    SECT_DATA: "__data",
    SECT_BSS: "__bss",
    SECT_COMMON: "__common",
    SEG_OBJC: "__OBJC",
    SECT_OBJC_MESSAGE_REFS: "__message_refs",
    SECT_OBJC_CLASS: "__class",
    SECT_OBJC_METACLASS: "__meta_class",
    SECT_OBJC_CLASS_REFS: "__cls_refs",
    SECT_OBJC_INSTANCE_METHODS: "__instance_meth",
    SECT_OBJC_INSTANCE_VARS: "__instance_vars",
    SECT_OBJC_IMAGE_INFO: "__image_info",
    SECT_OBJC_SYMBOLS: "__symbol_table",
    SECT_OBJC_MODULES: "__module_info",
    SECT_OBJC_STRINGS: "__selector_strs",
    SECT_OBJC_REFS: "__selector_refs",
    SEG_ICON: "__ICON",
    SECT_ICON_HEADER: "__header",
    SECT_ICON_TIFF: "__tiff",
    SEG_LINKEDIT: "__LINKEDIT",
    SEG_UNIXSTACK: "__UNIXSTACK",
    SEG_IMPORT: "__IMPORT",
    SECT_POINTERS: "__pointers",
    SECT_JUMP_TABLE: "__jump_table",
    SECT_CSTRING: "__cstring",
    SECT_CFSTRING: "__cfstring",
    SECT_DYLD: "__dyld",
    SECT_LITERAL4: "__literal4",
    SECT_LITERAL8: "__literal8",
    SECT_CONST: "__const",

    LC_SEGMENT: 0x1,
    LC_SYMTAB: 0x2,
    LC_SYMSEG: 0x3,
    LC_THREAD: 0x4,
    LC_UNIXTHREAD: 0x5,
    LC_LOADFVMLIB: 0x6,
    LC_IDFVMLIB: 0x7,
    LC_IDENT: 0x8,
    LC_FVMFILE: 0x9,
    LC_PREPAGE: 0xa,
    LC_DYSYMTAB: 0xb,
    LC_LOAD_DYLIB: 0xc,
    LC_ID_DYLIB: 0xd,
    LC_LOAD_DYLINKER: 0xe,
    LC_ID_DYLINKER: 0xf,
    LC_PREBOUND_DYLIB: 0x10,
    LC_ROUTINES: 0x11,
    LC_SUB_FRAMEWORK: 0x12,
    LC_SUB_UMBRELLA: 0x13,
    LC_SUB_CLIENT: 0x14,
    LC_SUB_LIBRARY: 0x15,
    LC_TWOLEVEL_HINTS: 0x16,
    LC_PREBIND_CKSUM: 0x17,
    LC_LOAD_WEAK_DYLIB: 0x80000018,
    LC_SEGMENT_64: 0x19,
    LC_ROUTINES_64: 0x1a,
    LC_UUID: 0x1b,
    LC_RPATH: 0x8000001c,
    LC_CODE_SIGNATURE: 0x1d,
    LC_SEGMENT_SPLIT_INFO: 0x1e,
    LC_REEXPORT_DYLIB: 0x8000001f,

    N_STAB: 0xe0,
    N_PEXT: 0x10,
    N_TYPE: 0x0e,
    N_EXT: 0x01,
    N_UNDF: 0x0,
    N_ABS: 0x2,
    N_SECT: 0xe,
    N_PBUD: 0xc,
    N_INDR: 0xa,
    N_NO_DEAD_STRIP: 0x0020,
    N_DESC_DISCARDED: 0x0020,
    N_WEAK_REF: 0x0040,
    N_WEAK_DEF: 0x0080,
    N_REF_TO_WEAK: 0x0080,

    N_GSYM: 0x20,
    N_FNAME: 0x22,
    N_FUN: 0x24,
    N_STSYM: 0x26,
    N_LCSYM: 0x28,
    N_BNSYM: 0x2e,
    N_OPT: 0x3c,
    N_RSYM: 0x40,
    N_SLINE: 0x44,
    N_ENSYM: 0x4e,
    N_SSYM: 0x60,
    N_SO: 0x64,
    N_OSO: 0x66,
    N_LSYM: 0x80,
    N_BINCL: 0x82,
    N_SOL: 0x84,
    N_PARAMS: 0x86,
    N_VERSION: 0x88,
    N_OLEVEL: 0x8A,
    N_PSYM: 0xa0,
    N_EINCL: 0xa2,
    N_ENTRY: 0xa4,
    N_LBRAC: 0xc0,
    N_EXCL: 0xc2,
    N_RBRAC: 0xe0,
    N_BCOMM: 0xe2,
    N_ECOMM: 0xe4,
    N_ECOML: 0xe8,
    N_LENG: 0xfe,
    N_PC: 0x30,

    REFERENCE_TYPE: 0xf,
    REFERENCE_FLAG_UNDEFINED_NON_LAZY: 0,
    REFERENCE_FLAG_UNDEFINED_LAZY: 1,
    REFERENCE_FLAG_DEFINED: 2,
    REFERENCE_FLAG_PRIVATE_DEFINED: 3,
    REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY: 4,
    REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY: 5,
    REFERENCED_DYNAMICALLY: 0x0010
});

MachO.prototype = {
    initialize: function(filetype, cputype, flags, cpusubtype, endian) {
        this.segments = [];
        this.dylibs = [];
        this.dyld = null;
        this.cpustates = [];
        this.symbols = {};
        this.local_symbols = [];
        this.undef_symbols = [];
        this.ext_symbols = [];
        this.ext_relocs = [];
        this.local_relocs = [];
        this.indirect_symbols = [];
        this.num_symbols = 0;
        this.filetype = filetype;
        this.cputype = cputype;

        if (typeof flags == 'undefined') {
            flags = this.__class__.MH_TWOLEVEL;
            if (filetype == this.__class__.MH_EXECUTABLE)
                flags |= this.__class__.MH_NOUNDEFS;
            this.flags = flags;
        }

        if (typeof cpusubtype != 'undefined') {
            this.cpusubtype = cpusubtype;
        } else {
            switch (cputype & 0xff) {
            case this.__class__.CPU_TYPE_X86:
                this.cpusubtype = this.__class__.CPU_SUBTYPE_X86_ALL;
                break;
            case this.__class__.CPU_TYPE_POWERPC:
                this.cpusubtype = this.__class__.CPU_SUBTYPE_POWERPC_ALL;
                break;
            default:
                throw "Cannot determine CPU subtype";
            }
        }
        if (typeof endian != 'undefined') {
            this.endian = endian; // false => little, true => big
        } else {
            switch (cputype & 0xff) {
            case this.__class__.CPU_TYPE_X86:
                this.endian = false;
                break;
            case this.__class__.CPU_TYPE_POWERPC:
                this.endian = true;
                break;
            default:
                throw "Cannot determine endian type";
            }
        }
    },

    addSegment: function(name) {
        var retval = new this.__class__.Segment(name);
        this.segments.push(retval);
        return retval;
    },

    findSegment: function(name) {
        for (var i = 0; i < this.segments.length; i++) {
            var seg = this.segments[i];
            if (seg.name == name)
                return seg;
        }
        return null;
    },

    convertVersionString: function(str) {
        if (typeof str == 'number')
            return str;
        if (typeof str != 'string')
            str = str.toString();
        var g = /^(\d+).(\d+).(\d+)$/.exec(str);
        return (parseInt(g[1]) << 16) | (parseInt(g[2]) << 8) | (parseInt(g[3]));
    },

    addDynamicLibrary: function(rpath, current_version, compatibility_version) {
        var entry = {
            path: rpath,
            timestamp: 0,
            current_version: this.convertVersionString(current_version),
            compatibility_version: this.convertVersionString(compatibility_version)
        };
        this.dylibs.push(entry);
        return entry;
    },

    setDynamicLinker: function(dyld) {
        this.dyld = dyld;
    },

    addIndirectSymbol: function(sym) {
        this.indirect_symbols.push(sym);
    },

    addLocalRelocationEntry: function(sym, addr, pcrel, len) {
        var entry = {
            symbol: sym,
            addr: addr,
            pcrel: pcrel,
            len: len
        };
        this.local_relocs.push(entry);
    },

    addExternalRelocationEntry: function(sym, addr, pcrel, len) {
        var entry = {
            symbol: sym,
            addr: addr,
            pcrel: pcrel,
            len: len
        };
        this.ext_relocs.push(entry);
    },

    addUnixThread: function(flavor) {
        var retval = null;
        switch (this.cputype) {
        case this.__class__.CPU_TYPE_X86:
            switch (flavor) {
            case this.__class__.i386_THREAD_STATE:
                retval = {
                    flavor: this.__class__.i386_THREAD_STATE,
                    fields: [
                        { name: 'eax',    type: 'U32' },
                        { name: 'ebx',    type: 'U32' },
                        { name: 'ecx',    type: 'U32' },
                        { name: 'edx',    type: 'U32' },
                        { name: 'edi',    type: 'U32' },
                        { name: 'esi',    type: 'U32' },
                        { name: 'ebp',    type: 'U32' },
                        { name: 'esp',    type: 'U32' },
                        { name: 'ss',     type: 'U32' },
                        { name: 'eflags', type: 'U32' },
                        { name: 'eip',    type: 'U32' },
                        { name: 'cs',     type: 'U32' },
                        { name: 'ds',     type: 'U32' },
                        { name: 'es',     type: 'U32' },
                        { name: 'fs',     type: 'U32' },
                        { name: 'gs',     type: 'U32' }
                    ],
                    eax: 0,
                    ebx: 0,
                    ecx: 0,
                    edx: 0,
                    edi: 0,
                    esi: 0,
                    ebp: 0,
                    esp: 0,
                    ss: 0,
                    eflags: 0,
                    eip: 0,
                    cs: 0,
                    ds: 0,
                    es: 0,
                    fs: 0,
                    gs: 0
                };
                break;
            default:
                throw "unsupported flavor";
            }
            break;
        case this.__class__.CPU_TYPE_X86_64:
            switch (flavor) {
            case this.__class__.x86_THREAD_STATE64:
                retval = {
                    flavor: this.__class__.x86_THREAD_STATE64,
                    fields: [
                        { name: 'rax', type: 'U64' },
                        { name: 'rbx', type: 'U64' },
                        { name: 'rcx', type: 'U64' },
                        { name: 'rdx', type: 'U64' },
                        { name: 'rdi', type: 'U64' },
                        { name: 'rsi', type: 'U64' },
                        { name: 'rbp', type: 'U64' },
                        { name: 'rsp', type: 'U64' },
                        { name: 'r8', type: 'U64' },
                        { name: 'r9', type: 'U64' },
                        { name: 'r10', type: 'U64' },
                        { name: 'r11', type: 'U64' },
                        { name: 'r12', type: 'U64' },
                        { name: 'r13', type: 'U64' },
                        { name: 'r14', type: 'U64' },
                        { name: 'r15', type: 'U64' },
                        { name: 'rip', type: 'U64' },
                        { name: 'rflags', type: 'U64' },
                        { name: 'cs', type: 'U64' },
                        { name: 'fs', type: 'U64' },
                        { name: 'gs', type: 'U64' }
                    ],
                    rax: 0,
                    rbx: 0,
                    rcx: 0,
                    rdx: 0,
                    rdi: 0,
                    rsi: 0,
                    rbp: 0,
                    rsp: 0,
                    r8: 0,
                    r9: 0,
                    r10: 0,
                    r11: 0,
                    r12: 0,
                    r13: 0,
                    r14: 0,
                    r15: 0,
                    rip: 0,
                    rflags: 0,
                    cs: 0,
                    fs: 0,
                    gs: 0
                };
                break;
            default:
                throw "unsupported flavor";
            }
            break;
        case this.__class__.CPU_TYPE_POWERPC:
            /* TBD */
        case this.__class__.CPU_TYPE_POWERPC64:
            /* TBD */
        default:
            throw "unsupported CPU type";
        }
        this.cpustates.push(retval);
        return retval;
    },

    addSymbol: function (sym, sect, flags, desc, addr) {
        var entry = {
            name: sym,
            type: (sect == null ? this.__class__.N_ABS: this.__class__.N_SECT)
                    | (flags & (this.__class__.N_PEXT | this.__class__.N_EXT)),
            sect: sect,
            desc: desc,
            value: addr
        };
        this.symbols[sym] = entry;
        this.local_symbols.push(entry);
        this.num_symbols++;
    },

    addExternalSymbol: function (sym, undef, desc, lib) {
        var entry = {
            name: sym,
            type: undef ? this.__class__.N_UNDF: this.__class__.N_EXT,
            sect: null,
            desc: desc,
            library: typeof lib == 'undefined' ? null: lib,
            value: 0
        };
        this.symbols[sym] = entry;
        this.num_symbols++;
        if (undef)
            this.undef_symbols.push(entry);
        else
            this.ext_symbols.push(entry);
        return entry;
    },

    estimateStringSize: function(str) {
        return ((str.length + 1 + 3) / 4 | 0) * 4;
    },

    estimateThreadStateSize: function(state) {
        var fields = state.fields;
        var retval = 0;
        for (var i = 0; i < fields.length; i++) {
            switch (fields[i].type) {
            case 'S8': case 'U8':
            case 'S16': case 'U16':
            case 'S32': case 'U32':
                retval += 4; /* 32-bit alignment */
                break;
            case 'S64': case 'U64':
                retval += 8;
                break;
            case 'float':
                retval += 8;
                break;
            }
        }
        return retval;
    },

    estimateCommandsSize: function() {
        var retval = 0;
        for (var i = 0; i < this.segments.length; i++) {
            var seg = this.segments[i];
            retval += this.__class__.LC_SIZE_SEGMENT +
                    this.__class__.SECT_SIZE * seg.sections.length;
        }
        if (this.num_symbols > 0)
            retval += this.__class__.LC_SIZE_SYMTAB;
        if (this.dyld != null) {
            retval += this.__class__.LC_SIZE_DYSYMTAB;
            retval += 4 * 2 + 4 + this.estimateStringSize(this.dyld.length);
        }
        for (var i = 0; i < this.cpustates.length; i++) {
            retval += 4 * 2 + 4 * 2 + this.estimateThreadStateSize(this.cpustates[i]);
        }
        for (var i = 0; i < this.dylibs.length; i++) {
            var dylib = this.dylibs[i];
            retval += 4 * 2 + 4 * 4 + this.estimateStringSize(dylib.path);
        }
        return retval;
    },

    serialize: function() {
        var __class__ = this.__class__;
        var self = this;
        var patches = {};

        var createBuffer = function() {
            return {
                buffer: new Buffer(),
                patches: {},

                addPlaceholder: function(name, type) {
                    this.patches[name] = [ this.buffer.anchor, type, null ];
                    this[type].call(this, 0);
                },
                setValue: function(name, value) {
                    this.patches[name][2] = value;
                },
                applyPatches: function() {
                    var anchor = this.buffer.anchor;
                    for (var i in this.patches) {
                        if (!this.patches.hasOwnProperty(i))
                            continue;
                        var patch = this.patches[i];
                        this.buffer.seek(patch[0]);
                        this[patch[1]].call(this, patch[2]);
                    }
                    this.buffer.anchor = anchor;
                },
                U8: function(v) { return this.buffer.U8(v); },
                U16: self.endian ? function(v) { this.buffer.U16BE(v); }:
                                   function(v) { this.buffer.U16LE(v); },
                U32: self.endian ? function(v) { this.buffer.U32BE(v); }:
                                   function(v) { this.buffer.U32LE(v); },
                U64: self.endian ? function(v) { this.buffer.U64BE(v); }:
                                   function(v) { this.buffer.U64LE(v); },
                S: function(v) { return this.buffer.S(v); },
                padZero: function(l) { return this.buffer.pad(l, "\0"); },
                getLength: function() { return this.buffer.length; }
            };
        };

        var linkedit_seg = this.findSegment(__class__.SEG_LINKEDIT);
        if (linkedit_seg == null) {
            linkedit_seg = this.addSegment(__class__.SEG_LINKEDIT);
        }

        var d = createBuffer();
        d.U32(0xfeedface);
        d.U32(this.cputype);
        d.U32(this.cpusubtype);
        d.U32(this.filetype);
        d.addPlaceholder('ncmds', 'U32');
        d.addPlaceholder('sizeofcmd', 'U32');
        d.U32(self.flags);

        var ncmds = 0;
        var sizeofcmd = d.getLength();
        for (var i = 0; i < self.segments.length; i++) {
            var seg = self.segments[i];

            d.U32(__class__.LC_SEGMENT);
            d.U32(__class__.LC_SIZE_SEGMENT +
                    __class__.SECT_SIZE * seg.sections.length);
            d.S(seg.name);
            d.padZero(16 - seg.name.length);
            d.U32(seg.vmaddr);
            d.U32(seg.vmsize);
            d.U32(seg.fileoff);
            d.U32(seg.filesize);
            d.U32(seg.maxprot);
            d.U32(seg.initprot);
            d.U32(seg.nsect);
            d.U32(seg.flags);

            for (var j = 0; j < seg.sections.length; j++) {
                var sect = seg.sections[j];
                d.S(sect.name);
                d.padZero(16 - sect.name.length);
                d.S(seg.name);
                d.padZero(16 - seg.name.length);
                d.U32(sect.addr);
                d.U32(sect.sjze);
                d.U32(sect.offset);
                d.U32(sect.aljgn);
                d.U32(sect.reloff);
                d.U32(sect.nreloc);
                d.U32(sect.flags);
                d.U32(0);
                d.U32(0);
            }
            ++ncmds;
        }

        if (this.num_symbols > 0) {
            d.U32(__class__.LC_SYMTAB);
            d.U32(__class__.LC_SIZE_SYMTAB);
            d.addPlaceholder('symoff', 'U32');
            d.U32(self.num_symbols);
            d.addPlaceholder('stroff', 'U32');
            d.addPlaceholder('strsize', 'U32');
            ++ncmds;
        }

        if (self.dyld != null) {
            d.U32(__class__.LC_DYSYMTAB);
            d.U32(__class__.LC_SIZE_DYSYMTAB);
            d.addPlaceholder('ilocalsym', 'U32');
            d.U32(self.local_symbols.length);
            d.addPlaceholder('iextdefsym', 'U32');
            d.U32(self.ext_symbols.length);
            d.addPlaceholder('iundefsym', 'U32');
            d.U32(self.undef_symbols.length);
            d.addPlaceholder('tocoff', 'U32');
            d.addPlaceholder('ntoc', 'U32');
            d.addPlaceholder('modtaoff', 'U32');
            d.addPlaceholder('nmodtab', 'U32');
            d.addPlaceholder('extrefsymoff', 'U32');
            d.addPlaceholder('nextrefsymsf', 'U32');
            d.addPlaceholder('indirectsymoff', 'U32');
            d.U32(self.indirect_symbols.length);
            d.addPlaceholder('extreloff', 'U32');
            d.U32(self.ext_relocs.length);
            d.addPlaceholder('locreloff', 'U32');
            d.U32(self.local_relocs.length);
            ++ncmds;
        }
        for (var i = 0; i < self.cpustates.length; i++) {
            var state = self.cpustates[i];
            var fields = state.fields;
            d.U32(__class__.LC_UNIXTHREAD);
            d.addPlaceholder('unixthread_len', 'U32');
            d.U32(state.flavor);
            d.addPlaceholder('unixthread_count', 'U32');
            var len = d.getLength();
            for (var j = 0; j < fields.length; j++) {
                d[fields[j].type].call(d, state[fields[j].name]);
            }
            len = d.getLength() - len;
            d.setValue('unixthread_count', (len + 3) / len | 0);
            d.setValue('unixthread_len', len + 4 * 4);
            ++ncmds;
        }
        for (var i = 0; i < self.dylibs.length; i++) {
            var dylib = self.dylibs[i];
            var estimated_string_size = self.estimateStringSize(dylib.path);
            d.U32(__class__.LC_LOAD_DYLIB);
            d.U32(4 * 2 + 4 * 4 + estimated_string_size);
            d.U32(dylib.timestamp);
            d.U32(dylib.current_version);
            d.U32(dylib.compatibility_version);
            d.S(dylib.path);
            d.padZero(estimated_string_size - dylib.path.length);
            ++ncmds;
        }
        sizeofcmd = d.getLength() - sizeofcmd;
        d.setValue('ncmds', ncmds);
        d.setValue('sizeofcmd', sizeofcmd);

        d.applyPatches();
        console.log(d.getLength());
        return d.buffer.toString();
    }
};
